
/***************************************************************************
 *   jell - library                                                        *
 *                                                                         *
 *   Copyright (C) 2008 by kuerant                                         *
 *                         <kuerant@gmail.com>                             *
 *                                                                         *
 *   This library is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU Library General Public License as       *
 *   published by the Free Software Foundation; either version 2 of the    *
 *   License, or (at your option) any later version.                       *
 *                                                                         *
 *   This library is distributed in the hope that it will be usefull, but  *
 *   WITHOUT ANY WARRANTY; without even the implied warranty of            *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU      *
 *   Library General Public License for more details.                      *
 *                                                                         *
 *   You should have received a copy of the GNU Library General Public     *
 *   License along with this library; if not, write to the Free Software   *
 *   Foundation, Inc., 59 Temple Place - Suite 330, Boston,                *
 *   MA 02111-1307, USA                                                    *
 ***************************************************************************/

#ifndef JEFI_POOL_HPP
#define JEFI_POOL_HPP

#include <vector>
#include <set>

namespace   jell
{

    /**
     * General purpose Pool.
     * Object can be 'leased' from pool,
     * and 'released' back to pool.
     * All access is synchronized.
     */
    template<class T>
    class Pool
    {
    private :
        typedef std::vector<T *>   __vtp;
        typedef std::set<T *>      __stp;
        typedef typename __vtp::iterator    __vtp_i;
        typedef typename __stp::iterator    __stp_i;

    public:

        /**
         * Creates Pool with initial size and max size.
         * 'initial' objects are created immediately.
         * Later Pool can automatically grow up to 'max_'.
         */
        Pool(size_t block_size_=1, size_t initial_=8, size_t max_=262144)
            : block_size(block_size_), max(max_),_count(0)
        {
            for(size_t i=0;i<initial_;i++)
                freepool.push_back(create());
        }

        ~Pool()
        {
            if ( 1 == block_size ) {
                for(__vtp_i i=freepool.begin(); i!=freepool.end(); ++i)
                    delete *i;
                for(__stp_i i=usedpool.begin(); i!=usedpool.end(); ++i)
                    delete *i;
            }
            else {
                for(__vtp_i i=freepool.begin(); i!=freepool.end(); ++i) {
                    T*  _t = *i;
                    delete [] _t;
                }
                for(__stp_i i=usedpool.begin(); i!=usedpool.end(); ++i) {
                    T*  _t = *i;
                    delete [] _t;
                }
            }
        }

        /**
         * Lease object from pool. After you are done with it
         * 'release' it back. If no instance availiable this
         * method will create new one. If pool is reached its
         * maximum capacity this method will block until some
         * instance is is released.
         */
        T *lease()
        {
            while(true) {
                if(freepool.size()==0) {
                    if(usedpool.size() < max) {
                        // create new instance
                        T* t = create();
                        usedpool.insert(t);
                        return t;
                    }
                    else {
                        // too many memory used
                        throw std::bad_alloc();
                    }
                }
                else {
                    //get one from free pool
                    __vtp_i m=freepool.begin();
                    T*  t = *m;
                    usedpool.insert(t);
                    freepool.erase(m);

                    return (t);
                }
            }
        }

        /**
         * Releases instance back to pool.
         */
        void release(T *t)
        {
            usedpool.erase(t);
            freepool.push_back(t);
        }

    public  :
        size_t  capacity(void)   const  { return max; }
        size_t  count(void)      const  { return _count; }
        size_t  count_used(void) const  { return usedpool.size(); }
        size_t  count_free(void) const  { return freepool.size(); }

    private :

        /**
         * creates new instance. This method is called by pool
         * when it decides to create new instance. It could be overloaded
         * to provide custom object creation code.
         */
        T *create()
        {
            // default implementation using empty constructor
            T*  t = NULL;

            if (1 == block_size) {
                t = new T();
            }
            else {
                t = new T[ block_size ];
            }

            ++_count;
            return  t;
        }

    private:
        size_t block_size;
        size_t max;
        size_t _count;

        std::vector<T *> freepool;
        std::set   <T *> usedpool;

    };

}   // namespace jell

#endif  // JEFI_POOL_HPP

